/*
 * Copyright 2007 Daniel Spiewak
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at
 * 
 *	    http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.java.ao.schema;

import java.io.IOException;
import java.io.InputStream;

import net.java.ao.EntityManager;
import net.java.ao.RawEntity;

/**
 * <p>A simple table name converter which imposes a set of regular-expression
 * rules to pluralize names generated by the delegate converter.  Unlike
 * most table name converters, this one does not actually generate a table
 * name from a class.  Rather, it takes a name generated by another converter
 * and applies some hard-coded rules to pluralize the result.  (these rules
 * are contained within the "/net/java/ao/schema/englishPluralRules.properties"
 * file).  The default delegate converter is {@link CamelCaseTableNameConverter}</p>
 * 
 * <p>Unfortunately, due to complexities innate to the English language,
 * automatic pluralization is never very accurate.  The sheer number of
 * irregular nouns, coupled with the different conjugations which can
 * unrecognizably mangle even an "every day" noun makes it extremely difficult
 * to define generic rules which can control pluralization.  ActiveObjects
 * attempts to uphold the highest standards of quality in its pluralization
 * engine by imposing rigorous tests using a wide variety of dictionary words.
 * However, the pluralization should be considered experimental at best.
 * Applications using pluralization in a production environment will often have
 * the need to define rules manually (thus the {@link #addPatternMapping(String, String)}
 * method).  It is for these reasons that pluralization is not enabled by
 * default (as it is in other ORMs).</p>
 * 
 * <p>To enable table name pluralization, simply set the name converter for
 * the {@link EntityManager} in question to an instance of this class.  Thus:</p>
 * 
 * <pre>EntityManager em = ...
 * m.setTableNameConverter(new PluralizedNameConverter());</pre>
 * 
 * <p>Although this class will delegate to any valid {@link TableNameConverter}
 * implementation, it will provide optimal functionality when used in conjunction
 * with a subclass of {@link AbstractTableNameConverter}.</p>
 * 
 * @author Daniel Spiewak
 */
public class PluralizedNameConverter extends AbstractTableNameConverter {
	private TableNameConverter delegate;
	
	/**
	 * Creates a new pluralizing table name converter using a new instance of
	 * {@link CamelCaseTableNameConverter} as a delegate.  Suitable for most
	 * use-cases.
	 */
	public PluralizedNameConverter() {
		this(new CamelCaseTableNameConverter());
	}
	
	/**
	 * Creates a new pluralizing table name converter using the specified name
	 * converter as a delegate.  This constructor provides for chaining with
	 * another name converter, thus allowing a great deal of flexibility in
	 * pluralizing table names of various conventions.
	 * 
	 * @param delegateConverter	The table name converter to which raw table name
	 * 		requests will be delegated (with the results being pluralized by
	 * 		this class).  Should be an instance of {@link AbstractTableNameConverter}.
	 */
	public PluralizedNameConverter(TableNameConverter delegateConverter) {
		OrderedProperties rules = new OrderedProperties();
		
		InputStream is = PluralizedNameConverter.class.getResourceAsStream(
				"/net/java/ao/schema/englishPluralRules.properties");
		
		try {
			rules.load(is);
		} catch (IOException e) {
			return;
		} finally {
			try {
				is.close();
			} catch (IOException e) {
			}
		}
		
		addPatternMappings(rules, rules.iterator());
		
		delegate = delegateConverter;
	}
	
	/**
	 * Returns the delegate name converter used for all pre-pluralization
	 * conversions.
	 */
	public TableNameConverter getDelegate() {
		return delegate;
	}
	
	@Override
	protected String convertName(Class<? extends RawEntity<?>> entity) {
		return delegate.getName(entity);
	}
	
	@Override
	protected String postProcessName(String back) {
		if (delegate instanceof AbstractTableNameConverter) {
			return ((AbstractTableNameConverter) delegate).postProcessName(back);
		}
		
		return back;
	}
}
